<?php
$dbh = null;

$xmlrpc_methods = array();
$xmlrpc_methods['method_not_found']          = 'XMLRPC_method_not_found';
$xmlrpc_methods['bmanager.get_users']        = 'bmanager_get_users';
$xmlrpc_methods['bmanager.get_my_filesets']  = 'bmanager_get_my_filesets';
$xmlrpc_methods['bmanager.get_my_subscribed_filesets']  = 'bmanager_get_my_subscribed_filesets';
$xmlrpc_methods['bmanager.publish_file']     = 'bmanager_publish_file';
$xmlrpc_methods['bmanager.add_user']         = 'bmanager_add_user';
$xmlrpc_methods['bmanager.login']            = 'bmanager_login';
$xmlrpc_methods['bmanager.logout']           = 'bmanager_logout';

function XMLRPC_method_not_found($methodName){
  XMLRPC_error("2", "The method you requested, '$methodName', was not found.", WEBLOG_XMLRPC_USERAGENT);
}

function bmanager_login($params){
  /* $session_id = bmanager.login(login, password) 
     logs in to the server. 
  */ 
  global $dbh;
  $login = $params[0];
  $password = $params[1];
  validate_login($login);
  validate_password($password);

  $sha1password = sha1( $password );
  $result = mysql_query("SELECT id FROM user WHERE login='$login' AND password='$sha1password'", $dbh) or sql_error($dbh);
  if($row = mysql_fetch_assoc($result)){
    $user_id = $row['id'];
  }
  if(!isset($user_id)){
    error("Login failed for user $login. '$password' $sha1password");
  }

  $session_id = md5( $login . time());
  validate_session_id($session_id);
  
  $result = mysql_query("INSERT INTO session (id,user_id) VALUES ('$session_id','$user_id')", $dbh) or sql_error($dbh);
  response($session_id);
}

function bmanager_logout($params){
  /*  $success = bmanager.logout(session_id)   
      logs out of the server
  */
  global $dbh;
  $session_id = $params[0];
  validate_session_id($session_id);

  $result = mysql_query("DELETE FROM session WHERE id='$session_id'") or sql_error($dbh);
  $res = array();
  if(mysql_affected_rows($dbh) == 1){
    $res[0] = 0;
    $res[1] = "logout ok";
  } else {
    $res[0] = 1;
    $res[1] = "no such session id";
  }
  response($res);
}

function bmanager_get_users($params){
  /* @users = bmanager.get_users($session_id)
    returns a list of all users */
  global $dbh;
  get_user_id($params[0]); // checks that we are logged in

  $result = mysql_query('SELECT login FROM user', $dbh) or sql_error($dbh);
  $users = array();
  while($row = mysql_fetch_assoc($result)){
    $users[] = $row['login'];
  }
  response($users);
}

function bmanager_get_my_filesets($params){
  global $dbh;
  $user_id = get_user_id($params[0]); // validates login too

  // get all the filesets
  $result = mysql_query("SELECT id, name FROM fileset WHERE user_id=$user_id", $dbh) or sql_error($dbh);
  $filesets = array();
  while($row = mysql_fetch_assoc($result)){
    $fs_id = $row['id'];
    $fs_name = $row['name'];

    $files = get_files_in_fileset($fs_id);

    $filesets[] = array($fs_id, $fs_name, $files);
  }
  response($filesets);
}

function bmanager_get_my_subscribed_filesets($params){
  global $dbh;
  $user_id = get_user_id($params[0]); // validates login too

  // get all the subscribed filesets
  $result = mysql_query("SELECT fs.id as id, fs.name as name FROM fileset fs, subscription s WHERE s.user_id=$user_id AND s.fileset_id=fs.id", $dbh) or sql_error($dbh);
  $filesets = array();
  while($row = mysql_fetch_assoc($result)){
    $fs_id = $row['id'];
    $fs_name = $row['name'];

    // check if the user has permission to subscribe to this fileset
    $aresult = mysql_query("SELECT count(*) FROM subscription_allow WHERE user_id=$user_id AND fileset_id=$fs_id", $dbh) or sql_error($dbh);
    $fs_allow = 0;
    if($count = mysql_fetch_row($aresult))
      if($count[0] == 1)
	$fs_allow = 1;
    
    if($fs_allow)
      $files = get_files_in_fileset($fs_id);
    else
      $files = array();

    $filesets[] = array($fs_id, $fs_name, $fs_allow, $files);
  }
  response($filesets);
}

function bmanager_publish_file($params){
  /* published a file:
      bmanager.publish_file(session_id, id, filesetname, size, torrent binary)
  */
  global $dbh;
  $user_id = get_user_id($params[0]); // validates login too
  $file_id = $params[1]; validate_file_id($file_id);
  $filesetname = $params[2]; validate_fileset_name($filesetname);
  $size = $params[3]; validate_size($size);
  validate_torrent($params[4]);
  $torrent = mysql_real_escape_string($params[4], $dbh); 
  
  /* get fileset_id

     if exists(id):
        do nothing
     else
        insert file

  */

  $result = mysql_query("SELECT id FROM fileset WHERE user_id=$user_id AND name='$filesetname'", $dbh) or sql_error($dbh);
  if($row = mysql_fetch_row($result))
    $fileset_id = $row[0];
  else
    error("Unknown fileset: $filesetname");

  $result = mysql_query("SELECT id FROM file WHERE fileset_id=$fileset_id AND id='$file_id'", $dbh) or sql_error($dbh);
  if($row = mysql_fetch_row($result))
    response('OK, file already exists');
  else {
    $result = mysql_query("INSERT INTO file (id, fileset_id, size, time, torrent) values ('$file_id', $fileset_id, $size, NOW(), '$torrent')", $dbh) or sql_error($dbh);
    response('OK, file published');
  }
}

function bmanager_add_user($params){
  /* adds a new user */
  global $dbh;
  $login = $params[0];
  $password = $params[1];
  validate_login($login);
  validate_password($password);

  $sha1password = sha1( $password );
  $result = mysql_query("SELECT user_id FROM user WHERE login='$login' AND password='$sha1password'", $dbh) or sql_error($dbh);

  response($users);
}

function get_files_in_fileset($fs_id){
  global $dbh;
  // get all the files in this fileset
  $fresult = mysql_query("SELECT id, size, time, torrent FROM file WHERE fileset_id=$fs_id", $dbh) or sql_error($dbh);
  $files = array();
  while($file = mysql_fetch_row($fresult))
    $files[] = $file;
  return $files;
}

/* validation functions */
function get_user_id($session_id) {
  global $dbh;
  validate_session_id($session_id);

  $result = mysql_query("SELECT user_id FROM session WHERE id='$session_id' AND time>(NOW()-15*50)", $dbh) or sql_error($dbh);
  if($row = mysql_fetch_assoc($result)){
    $user_id = $row['user_id'];
  }
  if(!isset($user_id)){
    error("You are not logged in.");
  }

  // renew the session timeout
  mysql_query("UPDATE session SET time=NOW() WHERE id='$session_id'") or sql_error($dbh);

  return $user_id;
}

function is_valid_login($login) {
  return preg_match('/^[a-zA-Z0-9_.:]{1,29}$/', $login);
}

function validate_login($login) {
  if(!is_valid_login($login)){
    error("Invalid login string: $login");
  }
}

function is_valid_password($password) {
  return preg_match('/^[a-zA-Z0-9_#%$@!.,;:]{1,29}$/', $password);
}

function validate_password($password) {
  if(!is_valid_password($password)){
    error("Invalid password string: $password");
  }
}

function is_valid_session_id($session_id) {
  return preg_match('/^[a-f0-9]{32}$/', $session_id);
}

function validate_session_id($session_id) {
  if(!is_valid_session_id($session_id)){
    error("Invalid session_id string: $session_id");
  }
}

function is_valid_file_id($id) {
  return preg_match('/^[a-f0-9]{40}$/', $id);
}

function validate_file_id($id) {
  if(!is_valid_file_id($id)){
    error("Invalid file_id string: $id");
  }
}

function is_valid_fileset_name($name) {
  return preg_match('/^[a-zA-Z0-9_.:]{1,29}$/', $name);
}

function validate_fileset_name($name) {
  if(!is_valid_fileset_name($name)){
    error("Invalid fileset name: $name");
  }
}

function is_valid_size($string) {
  // largest mysql bigint is 18446744073709551615
  return preg_match('/^[0-9]{1,20}$/', $string) && $string < 18446744073709551615;
}

function validate_size($string) {
  if(!is_valid_size($string)){
    error("Invalid size: $string");
  }
}

// allow torrents of less than 10MB size
function is_valid_torrent($string) {
  if(strlen($torrent) < 1024*1024*10)
    return 1;
  else
    return 0;
}

function validate_torrent($string) {
  if(!is_valid_torrent($string)){
    error("Torrent too long.");
  }
}




/* XMLRPC functions */
function response($resp) {
  XMLRPC_response(XMLRPC_prepare($resp), WEBLOG_XMLRPC_USERAGENT);
}

function error($string) {
    XMLRPC_error("3", $string, WEBLOG_XMLRPC_USERAGENT);
    exit;
}

/* database functions */

function sql_error($dbh) {
  error("Query error: ".mysql_error($dbh));
}

function init_db_connection() {
  global $dbh;
  $host = 'localhost';
  $user = 'martin';
  $password = null;
  $database = 'bmanager';
  $dbh = mysql_connect($host,$user,$password)
    or die('Could not connect: ' . mysql_error());
  mysql_select_db($database, $dbh);
}

function close_db_connection() {
  global $dbh;
  mysql_close($dbh);
}

?>
